home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / rules / prs2 / prs2main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  11.7 KB  |  413 lines

  1. /*---------------------------------------------------------------
  2.  *
  3.  * FILE
  4.  *    prs2main.c
  5.  *
  6.  * DESCRIPTION
  7.  *   top level PRS2 rule manager routines (called by the executor)
  8.  *
  9.  * INTERFACE ROUTINES
  10.  *   prs2main()
  11.  *
  12.  *   IDENTIFICATION
  13.  *    $Header: /private/postgres/src/rules/prs2/RCS/prs2main.c,v 1.16 1991/11/18 22:21:22 mer Exp $
  14.  * ----------------------------------------------------------------
  15.  */
  16.  
  17. #include "parser/parse.h"    /* RETRIEVE et all are defined here */
  18. #include "utils/log.h"
  19. #include "utils/rel.h"
  20. #include "access/heapam.h"
  21. #include "access/htup.h"
  22. #include "storage/buf.h"
  23. #include "rules/prs2.h"
  24. #include "rules/prs2stub.h"
  25. #include "nodes/plannodes.h"
  26. #include "nodes/execnodes.h"        /* which includes access/rulescan.h */
  27. #include "nodes/execnodes.a.h"
  28. #include "nodes/mnodes.h"
  29. #include "utils/mcxt.h"
  30.  
  31. /*------------------------------------------------------------------
  32.  *
  33.  * prs2main()
  34.  *
  35.  * Activate any rules that apply to the attributes specified.
  36.  *
  37.  *
  38.  * Explanation of arguments:
  39.  *   estate: the EState (executor state)
  40.  *   relationRuleInfo:
  41.  *    If the rule manager is called as part of a 'scan'
  42.  *    (i.e. the operation is a 'RETRIEVE' then this contains
  43.  *    some useful info about the scanned relation...
  44.  *   operation:
  45.  *    the kind of operation performed.
  46.  *    this can only be a RETRIEVE (everything else is ignored).
  47.  *   userId:
  48.  *    the user Id (currently ignored).
  49.  *   relation:
  50.  *    the relation where oldTuple & newTuple belong.
  51.  *   oldTuple:
  52.  *      If the operation is a RETRIEVE this is the base tuple, as
  53.  *      returned form the access methods (i.e. no rules have been applied
  54.  *      yet).
  55.  *      If the operation is a DELETE then this is the tuple to be
  56.  *      deleted.
  57.  *      If the operation is a REPLACE then this is the tuple
  58.  *      that is going to be replace with the new tuple.
  59.  *   oldBuffer:
  60.  *    the Buffer of the oldTuple.
  61.  *   newTuple:
  62.  *      If the operation is a APPEND then this is the new tuple
  63.  *      to be appended.
  64.  *      If the operation is a REPLACE then this is the new version
  65.  *      of the tuple (the one that will replace oldTuple).
  66.  *   newBuffer:
  67.  *    the Buffer of the newTuple.
  68.  *   rawTuple:
  69.  *    this is the same as the oldTuple, but exactly as returned
  70.  *    but the access methods. Normally, when a tuple is retrieved,
  71.  *    it is passed to the rule manager and if there are some 
  72.  *    backward chaining rules defined on it, some of its attribute
  73.  *     values will be changed. If the final operation was a replace, 
  74.  *     then oldTuple will be this changed tuple, ad rawTuple will be the
  75.  *    tuple, as it was returned by the AM with no rule activations.
  76.  *    'rawTuple' is a valid tuple if the operation is REPLACE,
  77.  *     and it is ignored in all other cases.
  78.  *   rawBuffer:
  79.  *    the buffer of the rawTuple.
  80.  *   attributeArray
  81.  *    An array of AttributeNumber. These are the attributes that
  82.  *      are affected by the specified operation.
  83.  *      If the operation is a RETRIEVE or a REPLACE then these
  84.  *      are the attributes that are retrieved or replaced.
  85.  *      In the xcase of APPEND & DELETE we assume that all the
  86.  *      attributes of the tuple are affected.
  87.  *   numberOfAttributes
  88.  *      the number of attributes in attributeArray.
  89.  *   returnedTupleP
  90.  *      If the operation was a RETRIEVE and the value of the
  91.  *      oldTuple has changed because of a rule, then this is 
  92.  *      the new tuple (that has to be used by the executor in
  93.  *      the place of the oldTuple.
  94.  *      If the operation was a REPLACE or APPEND and newTuple had
  95.  *      to be changed because of a rule, then this is the new tuple
  96.  *      that the executor has to use in the place of newTuple.
  97.  *   returnedBufferP
  98.  *      The Buffer of the returnedTuple (usually InvalidBuffer).
  99.  *
  100.  * Returned values:
  101.  *   PRS2_STATUS_TUPLE_UNCHANGED
  102.  *      Probably no applicable rules were found. Proceed as normal
  103.  *      returnedTupleP and returnedBufferP should NOT be used.
  104.  *   PRS2_STATUS_TUPLE_CHANGED
  105.  *    One or more rules were activated, (*returnedTupleP) should
  106.  *      be used (instead of oldTuple or newTuple).
  107.  *   PRS2_STATUS_INSTEAD
  108.  *      An instead was specified in the action part of a rule,
  109.  *      and therefore the executor must do nothing.
  110.  *
  111.  */
  112.  
  113. Prs2Status
  114. prs2Main(estate, retrieveRelationRuleInfo, operation, userId, relation,
  115.         oldTuple, oldBuffer,
  116.         newTuple, newBuffer,
  117.         rawTuple, rawBuffer,
  118.         attributeArray, numberOfAttributes,
  119.         returnedTupleP, returnedBufferP)
  120. EState estate;
  121. RelationRuleInfo retrieveRelationRuleInfo;
  122. int operation;
  123. int userId;
  124. Relation relation;
  125. HeapTuple oldTuple;
  126. Buffer oldBuffer;
  127. HeapTuple newTuple;
  128. Buffer newBuffer;
  129. AttributeNumberPtr attributeArray;
  130. int numberOfAttributes;
  131. HeapTuple *returnedTupleP;
  132. Buffer *returnedBufferP;
  133. {
  134.     Prs2Status status;
  135.     Buffer localBuffer;
  136.     Prs2EStateInfo prs2EStateInfo;
  137.     RelationRuleInfo updateRelationRuleInfo;
  138.     int topLevel;
  139.     Relation explainRelation;
  140.     MemoryContext oldMemContext;
  141.     GlobalMemory prs2MemContext;
  142.  
  143.     if (relation == NULL) {
  144.     /*
  145.      * This should not happen!
  146.      */
  147.     elog(WARN, "prs2main: called with relation = NULL");
  148.     }
  149.  
  150.     if (returnedBufferP == NULL) {
  151.     returnedBufferP = &localBuffer;
  152.     }
  153.  
  154.     explainRelation = get_es_explain_relation(estate);
  155.  
  156.     prs2EStateInfo = get_es_prs2_info(estate);
  157.     if (prs2EStateInfo == NULL) {
  158.     /*
  159.      * well, what do you know...
  160.      * this is the first time we call the rule manager and
  161.      * we are at the topmost level (i.e. no recursions
  162.      * yet. Allocate memory for the stack & initialize it.
  163.      */
  164.     prs2EStateInfo = prs2RuleStackInitialize();
  165.     set_es_prs2_info(estate, prs2EStateInfo);
  166.     }
  167.  
  168.     /*
  169.      * in order to avoid memory leaks, we will switch to another
  170.      * memory context, and after the dust settles we will just
  171.      * destroy all memory palloced but not pfreed.
  172.      *
  173.      * NOTE: this works just fine even if we have recursive calls
  174.      * to the executor/rule manager (even if the name of the
  175.      * new context is the same - it is never used...)
  176.      */
  177.     prs2MemContext = CreateGlobalMemory("*prs2Main");
  178.     oldMemContext = MemoryContextSwitchTo((MemoryContext)prs2MemContext);
  179.  
  180.     switch (operation) {
  181.     case RETRIEVE:
  182.         status = prs2Retrieve(
  183.                 prs2EStateInfo,
  184.                 retrieveRelationRuleInfo,
  185.                 explainRelation,
  186.                 oldTuple,
  187.                 oldBuffer,
  188.                 attributeArray,
  189.                 numberOfAttributes,
  190.                 relation,
  191.                 returnedTupleP,
  192.                 returnedBufferP);
  193.         break;
  194.     case DELETE:
  195.         updateRelationRuleInfo = get_es_result_rel_ruleinfo(estate);
  196.         status = prs2Delete(
  197.                 prs2EStateInfo,
  198.                 updateRelationRuleInfo,
  199.                 explainRelation,
  200.                 oldTuple,
  201.                 oldBuffer,
  202.                 rawTuple,
  203.                 rawBuffer,
  204.                 relation);
  205.         break;
  206.     case APPEND:
  207.         updateRelationRuleInfo = get_es_result_rel_ruleinfo(estate);
  208.         status = prs2Append(
  209.                 prs2EStateInfo,
  210.                 updateRelationRuleInfo,
  211.                 explainRelation,
  212.                 newTuple,
  213.                 newBuffer,
  214.                 relation,
  215.                 returnedTupleP,
  216.                 returnedBufferP);
  217.         break;
  218.     case REPLACE:
  219.         updateRelationRuleInfo = get_es_result_rel_ruleinfo(estate);
  220.         status = prs2Replace(
  221.                 prs2EStateInfo,
  222.                 updateRelationRuleInfo,
  223.                 explainRelation,
  224.                 oldTuple,
  225.                 oldBuffer,
  226.                 newTuple,
  227.                 newBuffer,
  228.                 rawTuple,
  229.                 rawBuffer,
  230.                 attributeArray,
  231.                 numberOfAttributes,
  232.                 relation,
  233.                 returnedTupleP,
  234.                 returnedBufferP);
  235.         break;
  236.  
  237.     default:
  238.         elog(WARN, "prs2main: illegal operation %d", operation);
  239.  
  240.     } /* switch */
  241.  
  242.     /*
  243.      * switch back to the old memory context
  244.      * and destroy all memory allocated under the prs2MemContext.
  245.      *
  246.      * NOTE: VERY IMPORTANT!
  247.      * If we have changed the tuple,then this new "returnedTuple"
  248.      * has been palloced under the 'prs2MemCOntext'.
  249.      * So, we have to recopy it under the other context for it
  250.      * to survive and live a long, happy life.
  251.      *
  252.      * Probably the right solution would be to switch temporarilly
  253.      * to the old context and then back to prs2MemContext when we
  254.      * were creating this returned tuple in the first place,
  255.      * but the code will become more complex and difficult to
  256.      * understand (while -of course- now it is a paradigm of
  257.      * simplicity and elegance....)
  258.      * Thus we could avoid this extra copy (so what, it is
  259.      * only a simple bcopy anyway....)
  260.      */
  261.     (void) MemoryContextSwitchTo(oldMemContext);
  262.     if (status == PRS2_STATUS_TUPLE_CHANGED) {
  263.     *returnedTupleP = palloctup(*returnedTupleP,
  264.                     *returnedBufferP,
  265.                     relation);
  266.     }
  267.     GlobalMemoryDestroy(prs2MemContext);
  268.  
  269.     /*
  270.      * XXX: do we HAVE to call prs2RuleStackFree ??
  271.      * I guess not really, we can just reuse the same stack
  272.      * over and over again...
  273.      */
  274.     /* if (topLevel) {
  275.      *     prs2RuleStackFree(prs2EStateInfo);
  276.      * }
  277.      */
  278.  
  279.     return(status);
  280. }
  281.  
  282. /*---------------------------------------------------------------------
  283.  * prs2MustCallRuleManager
  284.  *
  285.  * return true if the rule manager needs to be called, false
  286.  * otherwise (i.e. if there are absolutely no rules defined!).
  287.  *
  288.  * The main reason for this routine is for the executro to know whether
  289.  * is should call or not the rule manager. If there is no need to do so
  290.  * the executor can avoid setting up all the information the rule
  291.  * manager needs thus making things go faster.
  292.  *
  293.  * NOTE: in case of doubt, return true!
  294.  * NOTE2: we might make this routine slightly more clever.
  295.  * For instance even if there are some locks, they might not be relevant
  296.  * to the operation currently performed.
  297.  * 
  298.  *---------------------------------------------------------------------
  299.  */
  300. bool
  301. prs2MustCallRuleManager(relationRuleInfo, oldTuple, oldBuffer, operation)
  302. RelationRuleInfo relationRuleInfo;
  303. HeapTuple oldTuple;
  304. Buffer oldBuffer;
  305. int operation;
  306. {
  307.  
  308.     bool relLocksFlag;
  309.     bool oldTupLocksFlag;
  310.     bool stubsFlag;
  311.  
  312.     if (prs2GetNumberOfLocks(relationRuleInfo->relationLocks)==0)
  313.     relLocksFlag = false;
  314.     else
  315.     relLocksFlag = true;
  316.     
  317.     /*
  318.      * check for locks in 'old' tuple.
  319.      * However, if this is a tuple of the "pg_class" relation,
  320.      * ignore these locks.
  321.      */
  322.     if (oldTuple != NULL && !relationRuleInfo->ignoreTupleLocks) 
  323.     oldTupLocksFlag = !(HeapTupleHasEmptyRuleLock(oldTuple, oldBuffer));
  324.     else
  325.     oldTupLocksFlag = false;
  326.  
  327.     if (relationRuleInfo->relationStubs == NULL ||
  328.                 prs2StubIsEmpty(relationRuleInfo->relationStubs))
  329.     stubsFlag = false;
  330.     else
  331.     stubsFlag = true;
  332.  
  333.  
  334.     switch (operation) {
  335.     case RETRIEVE:
  336.         if (relLocksFlag || oldTupLocksFlag)
  337.         return(true);
  338.         else
  339.         return(false);
  340.         break;
  341.     case DELETE:
  342.         if (relLocksFlag || oldTupLocksFlag)
  343.         return(true);
  344.         else
  345.         return(false);
  346.     case APPEND:
  347.         if (stubsFlag || relLocksFlag)
  348.         return(true);
  349.         else
  350.         return(false);
  351.         break;
  352.     case REPLACE:
  353.         if (stubsFlag || relLocksFlag || oldTupLocksFlag)
  354.         return(true);
  355.         else
  356.         return(false);
  357.         break;
  358.     default:
  359.         elog(WARN, "prs2MustCallRuleManager: illegal operation %d",
  360.         operation);
  361.  
  362.     } /* switch */
  363.  
  364.     /*
  365.      * keep lint happy 
  366.      */
  367.  
  368.     return(false);
  369. }
  370.  
  371. /*========================== SHOW STATS ==========================*/
  372. /*
  373.  * We keep the following info:
  374.  *
  375.  * rulesTested:
  376.  *    Number of rules tested (i.e. how many times we tested the
  377.  *    qualification of a rule).
  378.  * rulesActivated:
  379.  *    Number of rules that were activated, i.e. the number of rules
  380.  *    that had their qualification evaluated to true.
  381.  */
  382.  
  383.  
  384. int Prs2Stats_rulesActivated;
  385. int Prs2Stats_rulesTested;
  386.  
  387. /*------------------------------------------------------------------
  388.  * ResetPrs2Stats
  389.  *------------------------------------------------------------------
  390.  */
  391. void
  392. ResetPrs2Stats()
  393. {
  394.     Prs2Stats_rulesTested = 0;
  395.     Prs2Stats_rulesActivated = 0;
  396. }
  397.  
  398.  
  399. /*------------------------------------------------------------------
  400.  * ShowPrs2Stats
  401.  *------------------------------------------------------------------
  402.  */
  403. void
  404. ShowPrs2Stats(statfp)
  405. FILE *statfp;
  406. {
  407.  
  408.     fprintf(statfp, "!\t%d rules_tested %d rules_activated\n",
  409.         Prs2Stats_rulesTested,
  410.         Prs2Stats_rulesActivated);
  411. }
  412.  
  413.